const config = require('./config')

const partialSet = new Set()

/**
 * @description 获取某个节点所有子孙节点
 * @param {Object} tree 总树
 * @param {Object} node 节点
 * @param {Array} node.children
 * @return {Array}
 */
function getAllChildren(tree,node,visited = new Set()){
	if (visited.has(node)) {
	    return [];
	  }
	visited.add(node);
  let tmp = [...node.children]
  node.children.forEach(v=>{
		if(!tree[v]){
			console.log(v)
		}
    tmp.push(...getAllChildren(tree,tree[v],visited))
  })
  return tmp
}

function paramsFormat(definitions,model){
	if(!definitions[model]){
		console.log('???',model)
	}
  const params = definitions[model].properties
  let content = `  data?:{${definitions[model].type}};  //${definitions[model].description||model||''}\n`
  return content
}


/**
 * @description 实体模型
 * @param {Object} definitions
 * @param {Array<String>} useModel
 * @returns
 */
function modelFormat(definitions,useModel){
    let str1 = ''
    let models = {}
    for (const key in definitions) {
      const children = []
      if (Object.hasOwnProperty.call(definitions, key)) {
         const element = definitions[key];
         const keyName = key?.replaceAll("«",'').replaceAll("»",'').replace(/\//g,'')
         let partialMark = partialSet.has(keyName)?'?':''
         let str2 = `  export interface ${keyName} { \n`

         const properties = element.properties
         for (const i in properties) {
           if (Object.hasOwnProperty.call(properties, i)) {
            const prop = properties[i];
            if(prop.$ref){
              const ref = prop.$ref.split(/(?<=^#\/definitions\/|«[^\/]*»$)/).pop().replace(/\//g, '').replaceAll("«",'').replaceAll("»",'')
              str2 += `   ${i}${partialMark}:${prop.type||ref||'object'}; //${ref}\n`
              if(ref&&!children[ref]){
                children.push(ref)
              }
            }else if(prop.type === 'array'){
              const item = prop.items
              if(item.$ref){
                const itemRef = item.$ref.split(/(?<=^#\/definitions\/|«[^\/]*»$)/).pop().replace(/\//g, '').replaceAll("«",'').replaceAll("»",'')
                str2 += `   ${i}${partialMark}:Array<${itemRef||item.type}>; //${itemRef}\n`
                if(itemRef&&!children[itemRef]){
                  children.push(itemRef)
                }
              }else{
                const type = item.type==='integer'?'number':item.type.replaceAll("«",'').replaceAll("»",'')
                str2 += `   ${i}${partialMark}:Array<${item.type}>;  //${prop.description||''}\n`
              }

            }else{
              const type = prop.type === 'integer'?'number':prop.type.replaceAll("«",'').replaceAll("»",'');
              str2 +=`   ${i}${partialMark}:${type};  //${prop.description||''}\n`
            }
           }
         }
         str2 += '  }\n\n'
         models[keyName] = {
           content:str2,
           children
         }
      }
    }
    [...new Set(getAllChildren(models,{content:'',children:useModel}))].forEach(v=>{
       if(models[v].content){
        str1 += models[v].content
       }
    })
    return `export namespace API {
${str1}
}`
}

/**
 * @description 模板字符串输出
 * @param {Object} json
 * @param {String} requestLibPath
 * @param {Array<String>} includePath
 * @param {Array<String>} excludePath
 * @returns
 */
function controllerFormat(json) {
  const basePath = json.basePath;
  const paths = json.paths;
  const definitions = json.definitions;
  let result = {};
  let method = {};
  let item = null;
  let functionName = '';
  let urlkey = ''; // 形如/url/{key}的key
  const useModel = []
  //tags是后端控制器模块数组
  for (const i in json.tags) {
    if (Object.hasOwnProperty.call(json.tags, i)) {
      const element = json.tags[i];
      const name = element.description.replaceAll(' ','').replace('Controller','').trim()
      if(config.include.length>0&&!config.include.includes(name)) continue;
      if(config.exclude.length>0&&config.include.includes(name)) continue;
      result[element.name] = {
        name,
        context: '',
        models:[]
      }
    }
  }

  for (const path in paths) {
    if (Object.hasOwnProperty.call(paths, path)) {
       if(config.includePath.length>0&&!config.includePath.includes(path))continue;
       if(config.excludePath.length>0&&config.excludePath.includes(path))continue;

      const element = paths[path];
      // method一个path只有一个，如出现多个需要改写
      for (let i in element) {
        method = i;
      }

      item = element[method]
      if(!result[item['tags'][0]]) continue;
      let response = ''

      if(item.responses['200']?.schema?.$ref){
          const ref = item.responses['200']?.schema?.$ref.split(/(?<=^#\/definitions\/|«[^\/]*»$)/).pop().replace(/\//g, '')
          response = `${ref.replaceAll("«",'').replaceAll("»","")}`
          if(ref){
            result[item['tags'][0]].models.push(ref.replaceAll("«",'').replaceAll("»",""))
          }
      }

      urlkey = path
      .split('/')
      .filter((i) => /{([A-z0-9]+)}/g.exec(i))
      .map((i) => /{([A-z0-9]+)}/g.exec(i)[1]);

      functionName = path
      .replace(/{|}/g,'/')
      .replace(/-/g,'/')
      .split('/')
      .reduce((a,b,c)=>{
        if(method==='get' && c===1){
          return a+b
        }else{
          return (c===1?method:'')+a+b.replace(/(|^)[a-z]/, (L) => L.toUpperCase());
        }
      })

       let getParams = '';
       let postParams = '';
       let queryStr = '';

       item.parameters&&item.parameters.forEach(v=>{
          if(!v.type&&v?.schema?.$ref){
            const ref = v?.schema?.$ref?.split(/(?<=^#\/definitions\/|«[^\/]*»$)/).pop().replace(/\//g, '')
            result[item['tags'][0]].models.push(ref)
            partialSet.add(ref)
            v.type =`API.${ref}`
          }
          if(item.parameters.length === 1&&v.in!=='path'){
            v.in==='query'?v.name = 'params':v.name = 'data'
            v.in = 'path'
          }
          if(v.type){
            v.type = v.type.includes('integer'||'float'||'double')?'number':v.type
          }
          if(v.type === 'ref'||v.type === 'object'){
            v.type = 'ApiRequest'
          }
          if(v.in==='path'){
            queryStr += `,${v.name}?:${v.type}`
          }
          if(v.in==='query'){
            getParams += `  ${v.name}?:${v.type}; //${v.description}\n`
          }
          if(v.in === 'body'){
            postParams += `  ${v.name}?:${v.type}; //${v.description}\n`
          }
       })
       if(getParams!==''){
        getParams = `
interface ${functionName}Params {
${getParams.trimEnd()}
}
`
queryStr += `,params:${functionName}Params`
       }
       if(postParams!==''){
        postParams = `
interface ${functionName}Data {
${postParams.trimEnd()}
}
`
queryStr += `,data:${functionName}Data`
       }


	 if(!result[item['tags'][0]]){
		continue;
	 }

      result[item['tags'][0]].context += `
${getParams}
${postParams}
/**
 * @description ${item.summary}
 */
export async function ${functionName}(${queryStr.replace(',','')}){
   return axiosClient.request<${response?'API.'+response:'ApiResponse'}>({
     url:\`${path.replace(/({)/g, '${')}\`,
     headers: commonHeader,
     method:'${method.toUpperCase()}',${queryStr.includes('data')?'\n     data,':''}${queryStr.includes('params')?'\n     params':''}
   })
}
 `;
    }
  }

   for (const i in result) {
     if (Object.hasOwnProperty.call(result, i)) {
      let requestLibPath = ''
      if(config.requestLibPath instanceof Array){
        config.requestLibPath.forEach(v=>{
          requestLibPath += `${v}\n`
        })
      }else{
        requestLibPath = config.requestLibPath
      }
      useModel.push(...result[i].models);
       if(result[i].context){
        result[i].context = `${requestLibPath} \n${result[i].context}\n`
       }else{
         Reflect.deleteProperty(result,i)
       }
     }
   }
   return {result,useModel};
}


module.exports = {
  controllerFormat,modelFormat
}